package com.leyou.search.service;


import com.leyou.item.bo.SpuBo;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.SpecParam;
import com.leyou.item.pojo.Spu;
import com.leyou.search.clients.BrandClient;
import com.leyou.search.clients.CategoryClient;
import com.leyou.search.clients.GoodsClient;
import com.leyou.search.clients.SpecificationClient;
import com.leyou.search.pojo.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.utils.SearchRequest;
import com.leyou.search.utils.SearchResult;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class SearchService {


    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private SpecificationClient specificationClient;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private IndexService indexService;

    /**
     * 搜索页面分页
     *
     * @param request
     * @return
     */
    public SearchResult search(SearchRequest request) {

        String key = request.getKey();

        if (StringUtils.isBlank(key)) {
            //如果用户没有搜索条件，可以给默认值或者返回null
            return null;
        }

        Integer page = request.getPage() - 1;//page 从0开始
        Integer size = request.getSize();

        // 1.从创建查询构建起
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //2.查询
        //2.1对结果进行筛选
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"id", "skus", "subTitle"}, null));

        //2.2基本查询
//        queryBuilder.withQuery(QueryBuilders.matchQuery("all", key));


        //创建过滤查询条件
        QueryBuilder query = buildBasicQueryWithFilter(request);

        queryBuilder.withQuery(query);

        //2.3分页
        queryBuilder.withPageable(PageRequest.of(page, size));

        //进行聚合
        String CategoryAggName = "category"; //商品分类聚合名称
        String BrandAggName = "brand"; //品牌分类聚合名称

        //添加聚合条件
        queryBuilder.addAggregation(AggregationBuilders.terms(CategoryAggName).field("cid3"));
        queryBuilder.addAggregation(AggregationBuilders.terms(BrandAggName).field("brandId"));

        //3.返回结果
        AggregatedPage<Goods> search = (AggregatedPage<Goods>) this.goodsRepository.search(queryBuilder.build());

        LongTerms categoryTerms = (LongTerms) search.getAggregation(CategoryAggName);

        //获取category的桶数据
        List<LongTerms.Bucket> categoryTermsBuckets = categoryTerms.getBuckets();

        List<Long> cids = new ArrayList<>();
        //遍历获得category的id 即76
        categoryTermsBuckets.forEach(bucket ->
                cids.add(bucket.getKeyAsNumber().longValue()));


        LongTerms brandTerms = (LongTerms) search.getAggregation(BrandAggName);
        //获取brand的桶数据
        List<LongTerms.Bucket> brandTermsBuckets = brandTerms.getBuckets();

        List<Long> brandIds = new ArrayList<>();
        //遍历获取所有的brandid
        brandTermsBuckets.forEach(bucket -> {
            brandIds.add(bucket.getKeyAsNumber().longValue());
        });

        //TODO 获取到了品牌的id集合和分类的id集合，需要转成对象

        List<Brand> brands = this.brandClient.queryBrandByIds(brandIds);

        List<String> names = this.categoryClient.queryNameByIds(cids);


        //提取分类信息,转成对象
        List<Category> categorys = new ArrayList<>();

        for (int i = 0; i < names.size(); i++) {
            Category category = new Category();
            category.setId(cids.get(i));
            category.setName(names.get(i));
            categorys.add(category);
        }

        List<Map<String, Object>> specs = null;

        if (categorys.size() == 1) {

            specs = getSpces(categorys.get(0).getId(),query);
        }

        //4.解析结果
        long total = search.getTotalElements();
        long totalPage = (total + size - 1) / size;

        return new SearchResult(total, totalPage, search.getContent(), categorys, brands, specs);

    }

            //根据查询条件查到的参数，在进行聚合获取对应的值
    private List<Map<String, Object>> getSpces(Long cid, QueryBuilder query) {

        //根据分类查询规格参数
        List<SpecParam> specParams = this.specificationClient.querySpecParam(null, cid, true);

        List<Map<String, Object>> specs = new ArrayList<>();


        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //先进行查询，再把查询的结果进行聚合
        queryBuilder.withQuery(query);

        //添加查询条件
        specParams.forEach(spec -> {
            queryBuilder.addAggregation(AggregationBuilders.terms(spec.getName()).field("specs." + spec.getName() + ".keyword"));
        });
        //执行查询获取聚合结果
        AggregatedPage<Goods> search = (AggregatedPage<Goods>) this.goodsRepository.search(queryBuilder.build());


        specParams.forEach(specParam -> {
            String aggName = specParam.getName();

            StringTerms stringTerms = (StringTerms) search.getAggregation(aggName);
            List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
            List<String> values = new ArrayList<>();
            for (StringTerms.Bucket bucket : buckets) {
                values.add(bucket.getKeyAsString());
            }

            Map<String, Object> spec = new HashMap<>();
            spec.put("k", aggName);
            spec.put("options", values);
            specs.add(spec);
        });

        return specs;
    }


    /**
     * 过滤查询方法
     *
     * @param request
     * @return
     */
    private QueryBuilder buildBasicQueryWithFilter(SearchRequest request) {

        //构建布尔查询器
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        //基本查询条件
        queryBuilder.must(QueryBuilders.matchQuery("all", request.getKey()).operator(Operator.AND));

        //过滤条件构造器
        BoolQueryBuilder filterQueryBuider = QueryBuilders.boolQuery();

        //获取过滤条件
        Map<String, String> filter = request.getFilter();

        Set<Map.Entry<String, String>> set = filter.entrySet();

        //迭代Map
        for (Map.Entry<String, String> entry : set) {
            String key = entry.getKey();
            String value = entry.getValue();


            if (key != "cid3" && key != "brandId") {
                key="specs."+key+".keyword";
            }

            //字符串类型，进行term查询
            filterQueryBuider.must(QueryBuilders.termQuery(key,value));
        }
        //添加过滤条件

        queryBuilder.filter(filterQueryBuider);

        return queryBuilder;
    }




    public void createIndex(Long id){
        Spu spu = this.goodsClient.querySpuById(id);
        SpuBo spuBo = new SpuBo();
        BeanUtils.copyProperties(spu,spuBo);
        Goods goods = this.indexService.buildGoods(spuBo);
        this.goodsRepository.save(goods);
    }

    public void deleteIndex(Long id) {
        this.goodsRepository.deleteById(id);
    }


}
